home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-06
/
ipxstuff.zip
/
RKIPX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-03-09
|
43KB
|
1,500 lines
/***************************************************/
/***************************************************/
/* IPX LIBRARY ROUTINES */
/* (c) 1992 by R. Kvinnesland */
/***************************************************/
/***************************************************/
/* ------- */
/* ------- */
/* headers */
/* ------- */
/* ------- */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <dos.h>
#include <time.h>
#include <string.h>
#include <conio.h>
#include <io.h>
#include <fcntl.h>
#include <sys\stat.h>
#include "rkipx.h"
/* ------------------------------------- */
/* ------------------------------------- */
/* global variables */
/* ------------------------------------- */
/* ------------------------------------- */
unsigned IPXerrno; // latest IPX error
time_t IPXto = IPX_TIMEOUT; // secs to wait for IPX command
unsigned IPXtries = IPX_TRIES; // # times to retry RX/TX
unsigned IPXdatalen = MINIPXDATALEN; // size of IPX packet data buffer
/* -------------------------------- */
/* ---- I N T E R N A L U S E ---- */
/* -------------------------------- */
static void (*IPXAPI)(void);
/************************************************************************/
/************************************************************************/
/* IPX LOW-LEVEL FUNCTIONS */
/************************************************************************/
/************************************************************************/
unsigned IPXInstalled( void )
{
union REGS regs;
struct SREGS sregs;
regs.x.ax = IPX_MULTIPLEX;
int86x( DOS_MULTIPLEX_VECTOR, ®s, ®s, &sregs );
IPXAPI = MK_FP( sregs.es, regs.x.di );
return( regs.h.al );
}
/************************************************************************/
/************************************************************************/
unsigned IPXSocketOpen( BYTE *socket, BYTE longevity )
{
_DL = socket[0];
_DH = socket[1];
_AL = longevity;
_BX = SOCKET_OPEN;
IPXAPI();
socket[0] = _DL;
socket[1] = _DH;
_AH = 0;
return( _AX );
}
/**************************************************************************/
/**************************************************************************/
void IPXSocketClose( BYTE *socket )
{
_DL = socket[0];
_DH = socket[1];
_BX = SOCKET_CLOSE;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
unsigned IPXGetLocalTarget( LOCALTARGET *lt )
{
_ES = FP_SEG( (void far *)lt );
_SI = FP_OFF( (void far *)lt->INA.Network );
_DI = FP_OFF( (void far *)lt->ImmediateAddr );
_BX = GET_LOCAL_TARGET;
IPXAPI();
_AH = 0;
return( _AX );
}
/**************************************************************************/
/**************************************************************************/
void IPXSendPacket( EVENTCONTROLBLOCK *ecb )
{
_ES = FP_SEG( (void far *)ecb );
_SI = FP_OFF( (void far *)ecb );
_BX = SEND_PACKET;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
void IPXListenForPacket( EVENTCONTROLBLOCK *ecb )
{
_ES = FP_SEG( (void far *)ecb );
_SI = FP_OFF( (void far *)ecb );
_BX = LISTEN_FOR_PACKET;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
void IPXGetInternetworkAddress( INTNETADDR *ina )
{
_ES = FP_SEG( (void far *)ina );
_SI = FP_OFF( (void far *)ina );
_BX = GET_INTERNETWORK_ADDR;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
void IPXRelinquishControl( void )
{
_BX = RELINQUISH_CONTROL;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
void IPXDisconnectFromTarget( NETADDR *naddr )
{
_ES = FP_SEG( (void far *)naddr );
_SI = FP_OFF( (void far *)naddr );
_BX = DISCONNECT_FROM_TARGET;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
unsigned IPXCancelEvent( EVENTCONTROLBLOCK *ecb )
{
_ES = FP_SEG( (void far *)ecb );
_SI = FP_OFF( (void far *)ecb );
_BX = CANCEL_EVENT;
IPXAPI();
_AH = 0;
return( _AX );
}
/**************************************************************************/
/**************************************************************************/
unsigned IPXGetIntervalMarker( void )
{
_BX = GET_INTERVAL_MARKER;
IPXAPI();
return( _AX );
}
/**************************************************************************/
/**************************************************************************/
void IPXScheduleEvent( EVENTCONTROLBLOCK *ecb, unsigned delay )
{
_ES = FP_SEG( (void far *)ecb );
_SI = FP_OFF( (void far *)ecb );
_AX = delay;
_BX = SCHEDULE_EVENT;
IPXAPI();
return;
}
/**************************************************************************/
/**************************************************************************/
/* INTERNAL UTILITY FUNCTIONS */
/**************************************************************************/
/**************************************************************************/
int IPXTimeOutRT( EVENTCONTROLBLOCK *ecb,
time_t delay,
void (*RTfunc)(void) )
{
time_t start_time;
start_time = time( NULL );
while ( ecb->InUse )
{
IPXRelinquishControl();
if ( RTfunc != NULL )
{
RTfunc();
}
if ( (time( NULL ) - start_time) > delay ) // next FULL second!
{
IPXCancelEvent( ecb );
return( TRUE );
}
}
return( !TRUE );
}
/*************************/
/*************************/
/* returns TRUE if characters in string are legal hex digits */
int xatoxb( BYTE *d, char *s )
{
while( *s )
{
if ( !isxdigit( *s ) )
{
return( !TRUE );
}
*d = (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7') << 4;
if ( !isxdigit( *s ) )
{
return( !TRUE );
}
*d++ += (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7');
}
return( TRUE );
}
/* ======================================================= */
/* allows/ignores non-hex ASCII delimiters in string */
void xantoxb( BYTE *d, char *s, unsigned len )
{
while( len-- )
{
while( !isxdigit( *s ) )
s++;
*d = (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7') << 4;
while( !isxdigit( *s ) )
s++;
*d++ += (isdigit(*s) ? *s++ - '0' : toupper(*s++) - '7');
}
return;
}
/*************************************************************************/
/*************************************************************************/
void ShowECB( EVENTCONTROLBLOCK *ecb )
{
unsigned i;
printf( "\n" );
printf( "LINK ADDR: %04X:%04X\n",
(unsigned)((long)ecb->LinkAddr / SEGSIZE ),
(unsigned)((long)ecb->LinkAddr % SEGSIZE) );
printf( " ESR: %04X:%04X\n",
(unsigned)((long)ecb->ESR / SEGSIZE),
(unsigned)((long)ecb->ESR % SEGSIZE) );
printf( " IN USE: %02X\n",
ecb->InUse );
printf( "COMP CODE: %02X\n",
ecb->CompletionCode );
printf( " SOCKET: %02X %02X\n",
ecb->Socket[0],
ecb->Socket[1] );
printf( "IPX WrkSp: %02X %02X %02X %02X\n",
ecb->IPXWorkspace[0],
ecb->IPXWorkspace[1],
ecb->IPXWorkspace[2],
ecb->IPXWorkspace[3] );
printf( "Drv WrkSp: %02X %02X %02X %02X",
ecb->DriverWorkspace[0],
ecb->DriverWorkspace[1],
ecb->DriverWorkspace[2],
ecb->DriverWorkspace[3] );
printf( " %02X %02X %02X %02X",
ecb->DriverWorkspace[4],
ecb->DriverWorkspace[5],
ecb->DriverWorkspace[6],
ecb->DriverWorkspace[7] );
printf( " %02X %02X %02X %02X\n",
ecb->DriverWorkspace[8],
ecb->DriverWorkspace[9],
ecb->DriverWorkspace[10],
ecb->DriverWorkspace[11] );
printf( "Immd Addr: %02X %02X %02X %02X %02X %02X\n",
ecb->ImmediateAddr[0],
ecb->ImmediateAddr[1],
ecb->ImmediateAddr[2],
ecb->ImmediateAddr[3],
ecb->ImmediateAddr[4],
ecb->ImmediateAddr[5] );
printf( " FRAG CNT: %u\n", ecb->FragmentCnt );
for( i = 0; i < ecb->FragmentCnt; i++ )
{
printf( " FRAG %03u - @BUFR: %04X:%04X LEN: %u\n",
i+1,
(unsigned)((long)ecb->Fragment[i].BufAddr / SEGSIZE),
(unsigned)((long)ecb->Fragment[i].BufAddr % SEGSIZE),
ecb->Fragment[i].Len );
}
return;
}
/*************************************************************************/
/*************************************************************************/
void ShowIPXPacket( IPXHEADER *ipxhdr )
{
unsigned i;
printf( "\n" );
printf( " Checksum: %04X\n", HILOSWAP( ipxhdr->Chksum ) );
printf( " IPX Pkt Len: %u\n", HILOSWAP( ipxhdr->Len ) );
printf( " RX Data Len: %u\n", HILOSWAP( ipxhdr->Len ) - sizeof(IPXHEADER) );
printf( "TransprtCtrl: %02X\n", ipxhdr->TransportCtrl );
printf( " PacketType: %02X\n", ipxhdr->PacketType );
printf( " DestNetwork: %02X %02X %02X %02X\n",
ipxhdr->DestAddr.INA.Network[0],
ipxhdr->DestAddr.INA.Network[1],
ipxhdr->DestAddr.INA.Network[2],
ipxhdr->DestAddr.INA.Network[3] );
printf( " DestNode: %02X %02X %02X %02X %02X %02X\n",
ipxhdr->DestAddr.INA.Node[0],
ipxhdr->DestAddr.INA.Node[1],
ipxhdr->DestAddr.INA.Node[2],
ipxhdr->DestAddr.INA.Node[3],
ipxhdr->DestAddr.INA.Node[4],
ipxhdr->DestAddr.INA.Node[5] );
printf( " DestSocket: %02X %02X\n",
ipxhdr->DestAddr.Socket[0],
ipxhdr->DestAddr.Socket[1] );
printf( " SrceNetwork: %02X %02X %02X %02X\n",
ipxhdr->SrceAddr.INA.Network[0],
ipxhdr->SrceAddr.INA.Network[1],
ipxhdr->SrceAddr.INA.Network[2],
ipxhdr->SrceAddr.INA.Network[3] );
printf( " SrceNode: %02X %02X %02X %02X %02X %02X\n",
ipxhdr->SrceAddr.INA.Node[0],
ipxhdr->SrceAddr.INA.Node[1],
ipxhdr->SrceAddr.INA.Node[2],
ipxhdr->SrceAddr.INA.Node[3],
ipxhdr->SrceAddr.INA.Node[4],
ipxhdr->SrceAddr.INA.Node[5] );
printf( " SrceSocket: %02X %02X\n",
ipxhdr->SrceAddr.Socket[0],
ipxhdr->SrceAddr.Socket[1] );
return;
}
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/* HIGH-LEVEL APPLICATION PROGRAMMING IPX INTERFACE FUNCTIONS */
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/*******************************************************************/
/*******************************************************************/
/*
------------------------
------------------------
FUNCTION: IPXReceiveRT()
------------------------
------------------------
Receive data into a buffer or file from a non-specified sender.
NOTE:
The sender must know the internetwork address and socket of the
machine that is to receive its transmission(s), but the receiver
merely has to issue a LISTEN & can then receive from any sender.
----------
----------
PROTOTYPE:
----------
----------
unsigned IPXReceiveRT( long *BfrLen,
BYTE *FileOrBfr,
char *SocketStr,
void (*RTfunc)(void) );
---------
---------
INPUT(S):
---------
---------
BfrLen = 0 if receiving a file
OR
the maximum # of bytes that can be stored in a given buffer
FileOrBfr = (string) name of file (path optional) into which to write
the data that is received
OR
pointer to given byte buffer into which to store the data
that is received
SocketStr = 4 character hex-ASCII string of IPX Socket to
use for receiving. Note that certain NOVELL sockets
are reserved, and the caller is cautioned to use
socket numbers "40xx", e.g., "4010", "40A1", etc.
RTfunc = pointer to a function which is to be called during
time out loops when IPX command is pending. Set
to NULL if you don't need this "real time" capability.
----------
----------
RETURN(S):
----------
----------
0x00 - GOOD_IPX_RETURN - all went well.
0x10 - BAD_LOCAL_TARGET - the internal IPX call to find the sender's
local target failed. Check the global variable IPXerrno for the
specific reason, e.g.:
0xFA - DEST_NODE_PATH_NOT_FND - the 6-byte node address
specified in the received IPX packet parameter SrceAddr
could not be found. Either the packet was corrupted,
or the sending machine with that node has died.
0x11 - BAD_SOCKET_PARAM - the SocketStr parameter did not consist of
a string of four hex-ascii digits.
0x12 - BAD_SOCKET_OPEN - the attempt to open the socket specified in
SocketStr parameter failed. The global variable IPXerrno will contain
return code received from IPX. It can be one of the following:
0xFE - SOCKET_TABLE_FULL - each machine gets 20 sockets, so
this error should never occur unless other non-"well
behaved" IPX applications are running on the machine.
0xFF - SOCKET_ALREADY_OPEN - it will be closed upon return,
so try again. It is not ignored because at the point
of call the socket shouldn't have been open, and all
discrepancies will be caught and reported!
0x20 - BAD_TX_TRY - an attempt to send a packet failed, due to
failure of either the network or the configuration of the receiving
machine. Check the global IPXerrno to discern the problem.
It should be one of the following:
0xFC - EVENT_CANCELED - send request was canceled by
application due to timeout.
0xFD - FRAGMENT_SIZE_ERROR - malformed packet size, either
less than 30 bytes or greater than 576 bytes, or
the event control block's Fragment Count field was 0.
0xFE - DESTINATION_NOT_FOUND - the destination machine,
specified in the NETADDR parameter, is not on the
network or not powered up.
0xFF - NETWORK_FAILURE - network or hardware failure.
0x21 - BAD_RETRIES - the receiver, while awaiting data from the
sending machine, has exhausted its retry number & count series.
Check IPXerrno for:
0xFC - EVENT_CANCELED - listen request was canceled by
application due to timeout.
0xFD - FRAGMENT_SIZE_ERROR - either the event control block's
Fragment Count field was 0, or the receiver's buffer
space was too small to hold the incoming data.
0xFF - ECB_SOCKET_NOT_OPEN - Socket for listening has not
been opened by the application.
0x22 - BAD_RX_SEQ_NUM - the receiving machine has received a block
of data whose sequence number is unexpected. If this has occured,
a network failure has caused the transmission to become garbled,
or the sending machine had aborted the current send/received sequence
and restarted anew within the retry number & timeout series of the
receiving machine. Both scenarios are highly unlikely.
0x30 - BAD_FILE_OPEN - the file to be received, specified by
the FileOrBfr parameter, could not be opened. Check syntax of
ASCIIZ string to make sure path and filename are correct, and
don't forget to use double slashes in the string when specifying
a path! For example, "D:\MYPATH\MYFILE.DAT" is not a valid C
string. You must pass it as "D:\\MYPATH\\MYFILE.DAT".
0x31 - BAD_FILE_WRITE - problem writing to the file specified in the
parameter FileOrBfr, even though the file was successfully opened.
This should never occur, barring disk failure or some strange
interaction between the caller's program and other programs running
as background processes or TSR's.
0xBB - USER_TERMINATED - the user has chosen to abort the application
by hitting the two SHIFT keys & an ALT key during a send/receive sequence.
0xDD - IPX_NOT_PRESENT - IPX API interface was not detected. Make
sure NOVELL's IPX.COM or equivalent has been run before attempting to
access IPX functions.
-------------------------
-------------------------
APPLICATION CODE EXAMPLE:
-------------------------
-------------------------
#include "ipx.h"
#define RXSOCKET "4050"
#define RXBFRSIZE 8192
int main( void )
{
unsigned rc;
long len;
BYTE *RxBfr;
// receiving a file
len = 0;
rc = IPXReceiveRT( &len, "RXDATA.DAT", RXSOCKET, NULL );
if ( rc != GOOD_IPX_RETURN )
{
printf( "FUNCTION ERROR: %02X IPX ERROR: %02X", rc, IPXerrno );
// take appropriate error action here
return( -1 );
}
// receiving a buffer
RxBfr = calloc( 1, RXBFRSIZE );
if ( !RxBfr )
{
printf( "MEMORY ALLOCATION FAILURE!" );
return( -1 );
}
len = RXBFRSIZE;
rc = IPXReceiveRT( &len, RxBfr, RXSOCKET, NULL );
if ( rc != GOOD_IPX_RETURN )
{
printf( "FUNCTION ERROR: %02X IPX ERROR: %02X", rc, IPXerrno );
// take appropriate error action here
return( -1 );
}
return( 0 );
}
*/
/*******************************************************************/
/*******************************************************************/
unsigned IPXReceiveRT( long *BfrLen,
BYTE *FileOrBfr,
char *SocketStr,
void (*RTfunc)(void) )
{
int fhandle;
long totRX;
BYTE *RXptr;
unsigned rc, lenRX, retries;
int TXflg, fileflg;
BYTE Socket[2];
BYTE expected_seq;
NETADDR TXna;
BYTE *pIPXbfrRX, *pIPXbfrTX;
IPXHEADER *pIPXpktRX, *pIPXpktTX;
EVENTCONTROLBLOCK *pIPXecbRX, *pIPXecbTX;
LOCALTARGET *pLocalTarget;
/* -------------------------------------------------------------- */
/* check that IPX API has been installed or attempt to install it */
/* -------------------------------------------------------------- */
if (
!(IPXAPI)
&&
(IPXInstalled() != IPX_PRESENT)
)
{
return( IPX_NOT_PRESENT );
}
/* ------------------------------------------- */
/* open socket for peer-to-peer communications */
/* ------------------------------------------- */
if (
(strlen( SocketStr ) != (sizeof(Socket)*2)) // 2 ASCII chars per byte
||
!(xatoxb( Socket, SocketStr ))
)
{
return( BAD_SOCKET_PARAM );
}
IPXerrno = IPXSocketOpen( Socket, SOCKET_SHORT_LIVED );
if ( IPXerrno != IPX_SUCCESS )
{
if ( IPXerrno == SOCKET_ALREADY_OPEN )
/*
sure, we could just go ahead,
but the socket really shouldn't have been open at this point,
and until this library has been thoroughly shaken out,
(hopefully) ALL discrepancies will be caught & reported!
*/
{
IPXSocketClose( Socket );
}
return( BAD_SOCKET_OPEN );
}
/* -------------------- */
/* set the receive mode */
/* -------------------- */
fileflg = TRUE;
if ( *BfrLen )
{
RXptr = FileOrBfr;
fileflg = !TRUE;
}
/* ----------------------- */
/* attempt to open RX file */
/* ----------------------- */
if ( fileflg )
{
fhandle = open( FileOrBfr,
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
S_IREAD | S_IWRITE );
if ( fhandle == FILE_PROBLEM )
{
IPXSocketClose( Socket );
return( BAD_FILE_OPEN );
}
}
/* ------------------------- */
/* allocate necessary memory */
/* ------------------------- */
pIPXbfrRX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
pIPXbfrTX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
pIPXpktRX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
pIPXpktTX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
pIPXecbRX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
pIPXecbTX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
pLocalTarget = (LOCALTARGET *)calloc( 1, sizeof(LOCALTARGET) );
if (
pIPXbfrRX == NULL ||
pIPXbfrTX == NULL ||
pIPXpktRX == NULL ||
pIPXpktTX == NULL ||
pIPXecbRX == NULL ||
pIPXecbTX == NULL ||
pLocalTarget == NULL
)
{
IPXSocketClose( Socket );
*BfrLen = 0;
if ( fileflg )
{
close( fhandle );
unlink( FileOrBfr );
}
if ( pIPXbfrRX )
free( pIPXbfrRX );
if ( pIPXbfrTX )
free( pIPXbfrTX );
if ( pIPXpktRX )
free( pIPXpktRX );
if ( pIPXpktTX )
free( pIPXpktTX );
if ( pIPXecbRX )
free( pIPXecbRX );
if ( pIPXecbTX )
free( pIPXecbTX );
if ( pLocalTarget )
free( pLocalTarget );
return( BAD_MEMORY_ALLOC );
}
/* --------------------------- */
/* initialize ECBs/IPX packets */
/* --------------------------- */
memcpy( pIPXecbRX->Socket, Socket, sizeof(pIPXecbRX->Socket) );
pIPXpktRX->PacketType = IPX_PACKET_TYPE;
pIPXecbRX->FragmentCnt = 2;
pIPXecbRX->Fragment[0].BufAddr = (void *)pIPXpktRX;
pIPXecbRX->Fragment[0].Len = sizeof(IPXHEADER);
pIPXecbRX->Fragment[1].BufAddr = (void *)pIPXbfrRX;
pIPXecbRX->Fragment[1].Len = SEQLEN+IPXdatalen;
memcpy( pIPXecbTX->Socket, Socket, sizeof(pIPXecbTX->Socket) );
pIPXpktTX->PacketType = IPX_PACKET_TYPE;
pIPXecbTX->FragmentCnt = 2;
pIPXecbTX->Fragment[0].BufAddr = (void *)pIPXpktTX;
pIPXecbTX->Fragment[0].Len = sizeof(IPXHEADER);
pIPXecbTX->Fragment[1].BufAddr = (void *)pIPXbfrTX;
pIPXecbTX->Fragment[1].Len = SEQLEN+strlen( ACKSTR );
strcpy( pIPXbfrTX+SEQLEN, ACKSTR );
/* =================== */
/* DATA RX/ACK TX LOOP */
/* =================== */
expected_seq = FIRST_SEQ_NUM;
TXflg = !TRUE;
retries = 0;
totRX = 0;
while ( TRUE )
{
/* if user decides to break it off, then quit */
if ( USERBREAK )
{
rc = USER_TERMINATED;
break;
}
/* issue LISTEN for pending RX of data */
IPXListenForPacket( pIPXecbRX );
/* ----------------------------- */
/* issue SEND to ACK previous RX */
/* ----------------------------- */
if ( TXflg )
{
/* RX source address = TX destination address */
memcpy( &pIPXpktTX->DestAddr, &TXna, sizeof(NETADDR) );
/* must also fill immediate address of ECB */
memcpy( pLocalTarget, &TXna, sizeof(NETADDR) );
IPXerrno = IPXGetLocalTarget( pLocalTarget );
if ( IPXerrno != IPX_SUCCESS )
{
IPXCancelEvent( pIPXecbRX );
rc = BAD_LOCAL_TARGET;
break;
}
memcpy( pIPXecbTX->ImmediateAddr,
pLocalTarget->ImmediateAddr,
sizeof(pIPXecbTX->ImmediateAddr) );
/* retain RX seq # for ACK */
*pIPXbfrTX = *pIPXbfrRX;
/* send the ACK & check result of TX */
IPXSendPacket( pIPXecbTX );
IPXTimeOutRT( pIPXecbTX, IPXto, RTfunc );
IPXerrno = pIPXecbTX->CompletionCode;
if ( IPXerrno != IPX_SUCCESS )
{
IPXCancelEvent( pIPXecbRX );
rc = BAD_TX_TRY;
break;
}
/* ------------------------ */
/* TX was successfully sent */
/* ------------------------ */
/* if the previous RX data that we are now ACKing */
/* did not fill the RX buffer, consider it EOT */
if ( lenRX < IPXdatalen )
{
IPXCancelEvent( pIPXecbRX );
rc = GOOD_IPX_RETURN;
break;
}
} // end of if ( TXflg )
/* -------------- */
/* monitor LISTEN */
/* -------------- */
/* monitor result of pending LISTEN */
IPXTimeOutRT( pIPXecbRX, IPXto, RTfunc );
IPXerrno = pIPXecbRX->CompletionCode;
/* ----------------- */
/* RX was successful */
/* ----------------- */
if ( IPXerrno == IPX_SUCCESS )
{
/* if first RX then save Sender's address */
if ( !totRX )
{
memcpy( &TXna, &pIPXpktRX->SrceAddr, sizeof(NETADDR) );
}
/* ignore all but latest Sender */
if ( memcmp( &TXna, &pIPXpktRX->SrceAddr, sizeof(NETADDR) ) )
{
TXflg = !TRUE;
continue;
}
/* check sequence number */
if ( expected_seq != *pIPXbfrRX )
{
rc = BAD_RX_SEQ_NUM;
break;
}
/* if any data was received, then save it */
lenRX = HILOSWAP( pIPXpktRX->Len ) - (sizeof(IPXHEADER)+SEQLEN);
if ( lenRX )
{
/* data to be written to file */
if ( fileflg )
{
rc = write( fhandle, pIPXbfrRX+SEQLEN, lenRX );
if ( lenRX != rc )
{
rc = BAD_FILE_WRITE;
break;
}
}
/* data to be copied into buffer */
if ( !fileflg )
{
totRX += lenRX;
if ( *BfrLen < totRX )
{
rc = BAD_RX_BFR_LEN;
break;
}
memcpy( RXptr, pIPXbfrRX+SEQLEN, lenRX );
RXptr += lenRX;
}
} // end of if ( lenRX )
/* ACK is now owed to sender; clear retry cnts & bump seq # */
TXflg = TRUE;
retries = 0;
expected_seq++;
} // end of if ( IPXerrno == IPX_SUCCESS )
/* --------------------- */
/* RX was NOT successful */
/* --------------------- */
if ( IPXerrno != IPX_SUCCESS )
{
/* if maximum retries have been exhausted, then quit */
if ( retries++ >= IPXtries )
{
rc = BAD_RETRIES;
break;
}
} // end of if ( IPXerrno != IPX_SUCCESS )
} // end of while ( TRUE )
/* ---------------- */
/* bring it on home */
/* ---------------- */
IPXSocketClose( Socket );
/* if file mode, close it & delete it if something went wrong */
if ( fileflg )
{
close( fhandle );
if ( rc != GOOD_IPX_RETURN )
{
unlink( FileOrBfr );
}
}
/* if buffer mode, set number of bytes read into buffer */
if ( !fileflg )
{
*BfrLen = totRX;
if ( rc != GOOD_IPX_RETURN )
{
*BfrLen = 0;
}
}
/* free that mem! */
free( pIPXbfrRX );
free( pIPXbfrTX );
free( pIPXpktRX );
free( pIPXpktTX );
free( pIPXecbRX );
free( pIPXecbTX );
free( pLocalTarget );
return( rc );
}
/*******************************************************************/
/*******************************************************************/
/*
---------------------
---------------------
FUNCTION: IPXSendRT()
---------------------
---------------------
Send a file or buffer to specified destination machine
----------
----------
PROTOTYPE:
----------
----------
unsigned IPXSendRT( long *BfrLen,
BYTE *FileOrBfr,
char *SocketStr,
NETADDR *Destination,
void (*RTfunc)(void) );
---------
---------
INPUT(S):
---------
---------
BfrLen = 0 if sending a file
OR
the # of bytes to send from a given byte buffer
FileOrBfr = (string) name of file (path optional) to send
OR
pointer to given byte buffer from which to send data
SocketStr = 4 character hex-ASCII string of IPX Socket to
use for sending. Note that certain NOVELL sockets
are reserved, and the caller is cautioned to use
socket numbers "40xx", e.g., "4010", "40A1", etc.
Destination = structure containing Network Address, Node
Address, and receiving socket number of the
machine that is to receive the file/buffer data.
See IPX.H for structure layout; if needed, use
function xatoxb() for converting hex-ascii
strings to hex-binary bytes.
RTfunc = pointer to a function which is to be called during
time out loops when IPX command is pending. Set
to NULL if you don't need this "real time" capability.
----------
----------
RETURN(S):
----------
----------
0x00 - GOOD_IPX_RETURN - all went well.
0x10 - BAD_LOCAL_TARGET - the internal IPX call to find the receiver's
local target failed. Check the global variable IPXerrno for the
specific reason, e.g.:
0xFA - DEST_NODE_PATH_NOT_FND - the 6-byte node address
specified in the passed parameter Destination.INA.Node
could not be found. Either the node is non-extant, or
the machine with that node is not powered on.
0x11 - BAD_SOCKET_PARAM - the SocketStr parameter did not consist of
a string of four hex-ascii digits.
0x12 - BAD_SOCKET_OPEN - the attempt to open the socket specified in
SocketStr parameter failed. The global variable IPXerrno will contain
return code received from IPX. It can be one of the following:
0xFE - SOCKET_TABLE_FULL - each machine gets 20 sockets, so
this error should never occur unless other non-"well
behaved" IPX applications are running on the machine.
0xFF - SOCKET_ALREADY_OPEN - it will be closed upon return,
so try again. It is not ignored because at the point
of call the socket shouldn't have been open, and all
discrepancies will be caught and reported!
0x20 - BAD_TX_TRY - the attempt to send an IPX packet failed due to
a problem of either the network or the configuration of the sending
machine. Check the global IPXerrno to discern the problem. It should
be one of the following:
0xFC - EVENT_CANCELED - send request was canceled by
application due to timeout.
0xFD - FRAGMENT_SIZE_ERROR - malformed packet size, either
less than 30 bytes or greater than 576 bytes, or
the event control block's Fragment Count field was 0.
0xFE - DESTINATION_NOT_FOUND - the destination machine,
specified in the NETADDR parameter, is not on the
network or not powered up.
0xFF - NETWORK_FAILURE - network or hardware failure.
0x21 - BAD_RETRIES - the sender has been awaiting an acknowledgement
from the receiver for most recently sent data, and has exhausted its
retry number & count series. Check IPXerrno for:
0xFC - EVENT_CANCELED - listen request was canceled by
application due to timeout.
0xFD - FRAGMENT_SIZE_ERROR - either the event control block's
Fragment Count field was 0, or the receiver's buffer
space was too small to hold the incoming data.
0xFF - ECB_SOCKET_NOT_OPEN - Socket for listening has not
been opened by the application.
0x22 - BAD_RX_SEQ_NUM - the destination machine has transmitted an
acknowledgement to received data, but the sequence number does not
match the sequence number of the data that the sender transmitted.
If this problem occurs, either a network failure has caused the
transmission to become garbled, or the destination machine had
aborted the current send/received sequence and restarted anew
within the retry number & timeout series of the sender.
Both scenarios are highly unlikely.
0x23 - BAD_RX_SRCE_ADDR - the sending machine received a transmission
from a machine other than the expected receiver of the original trans-
mission. This should never occur, due to the fact that the sender
socket should be known at this point only to the receiver of the
message that the sender transmitted. If other machines transmitting
on the network are getting through to another sender unexpectedly, then
some application software debugging is in order, or special TSR programs
are running, the behavior of which should be monitored more stringently.
0x30 - BAD_FILE_OPEN - the file to be transmitted, specified by
the FileOrBfr parameter, could not be opened. Check syntax of
ASCIIZ string to make sure path and filename are correct, and
don't forget to use double slashes in the string when specifying
a path! For example, "D:\MYPATH\MYFILE.DAT" is not a valid C
string. You must pass it as "D:\\MYPATH\\MYFILE.DAT".
0x32 - BAD_FILE_READ - problem reading the file specified in the
parameter FileOrBfr, even though the file was successfully opened.
This should never occur, barring disk failure or some strange
interaction between the caller's program and other programs running
as background processes or TSR's.
0xBB - USER_TERMINATED - the user has chosen to abort the application
by hitting the two SHIFT keys & an ALT key during a send/receive sequence.
0xDD - IPX_NOT_PRESENT - IPX API interface was not detected. Make
sure NOVELL's IPX.COM or equivalent has been run before attempting to
access IPX functions.
-------------------------
-------------------------
APPLICATION CODE EXAMPLE:
-------------------------
-------------------------
#define TXSOCKET "4050"
#define TXBFRSIZE 8192
int main( void )
{
NETADDR na;
unsigned rc;
long len;
BYTE *TxBfr;
// hard-coded example of internetwork address of destination machine
xatoxb( na.INA.Network, "01234567" );
xatoxb( na.INA.Node, "0123456789AB" );
xatoxb( na.Socket, "4010" );
// sending a file
len = 0;
rc = IPXSendRT( &len, "TXDATA.DAT", TXSOCKET, &na, NULL );
if ( rc != GOOD_IPX_RETURN )
{
// take appropriate error action here
return( -1 );
}
// sending a buffer
TxBfr = calloc( 1, TXBFRSIZE );
if ( !TxBfr )
{
printf( "MEMORY ALLOCATION FAILURE!" );
return( -1 );
}
len = TXBFRSIZE;
rc = IPXSendRT( &len, TxBfr, TXSOCKET, &na, NULL );
if ( rc != GOOD_IPX_RETURN )
{
printf( "FUNCTION ERROR: %02X IPX ERROR: %02X", rc, IPXerrno );
// take appropriate error action here
return( -1 );
}
return( 0 );
}
*/
/*******************************************************************/
/*******************************************************************/
unsigned IPXSendRT( long *BfrLen,
BYTE *FileOrBfr,
char *SocketStr,
NETADDR *Destination,
void (*RTfunc)(void) )
{
int fhandle;
unsigned rc, lenTX, retries;
BYTE *TXptr;
int retryTXflg, fileflg;
BYTE Socket[2];
BYTE expected_seq;
BYTE *pIPXbfrRX, *pIPXbfrTX;
IPXHEADER *pIPXpktRX, *pIPXpktTX;
EVENTCONTROLBLOCK *pIPXecbRX, *pIPXecbTX;
LOCALTARGET *pLocalTarget;
/* ----------------------------------------------------------- */
/* check that IPX API has been installed or attempt to install */
/* ----------------------------------------------------------- */
if (
!(IPXAPI)
&&
(IPXInstalled() != IPX_PRESENT)
)
{
return( IPX_NOT_PRESENT );
}
/* ------------------------------------------- */
/* open socket for peer-to-peer communications */
/* ------------------------------------------- */
if (
(strlen( SocketStr ) != (sizeof(Socket)*2))
||
!(xatoxb( Socket, SocketStr ))
)
{
return( BAD_SOCKET_PARAM );
}
IPXerrno = IPXSocketOpen( Socket, SOCKET_SHORT_LIVED );
if ( IPXerrno != IPX_SUCCESS )
{
if ( IPXerrno == SOCKET_ALREADY_OPEN )
{
IPXSocketClose( Socket );
}
return( BAD_SOCKET_OPEN );
}
/* --------------------- */
/* set the transfer mode */
/* --------------------- */
fileflg = TRUE;
if ( *BfrLen )
{
TXptr = FileOrBfr;
fileflg = !TRUE;
}
/* ------------------------------- */
/* check that TX file is available */
/* ------------------------------- */
if ( fileflg )
{
fhandle = open( FileOrBfr, O_RDONLY | O_BINARY );
if ( fhandle == FILE_PROBLEM )
{
IPXSocketClose( Socket );
return( BAD_FILE_OPEN );
}
}
/* ------------------------- */
/* allocate necessary memory */
/* ------------------------- */
pIPXbfrRX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
pIPXbfrTX = (BYTE *)calloc( 1, SEQLEN+IPXdatalen );
pIPXpktRX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
pIPXpktTX = (IPXHEADER *)calloc( 1, sizeof(IPXHEADER) );
pIPXecbRX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
pIPXecbTX = (EVENTCONTROLBLOCK *)calloc( 1, sizeof(EVENTCONTROLBLOCK) );
pLocalTarget = (LOCALTARGET *)calloc( 1, sizeof(LOCALTARGET) );
if (
pIPXbfrRX == NULL ||
pIPXbfrTX == NULL ||
pIPXpktRX == NULL ||
pIPXpktTX == NULL ||
pIPXecbRX == NULL ||
pIPXecbTX == NULL ||
pLocalTarget == NULL
)
{
IPXSocketClose( Socket );
if ( fileflg )
close( fhandle );
if ( pIPXbfrRX )
free( pIPXbfrRX );
if ( pIPXbfrTX )
free( pIPXbfrTX );
if ( pIPXpktRX )
free( pIPXpktRX );
if ( pIPXpktTX )
free( pIPXpktTX );
if ( pIPXecbRX )
free( pIPXecbRX );
if ( pIPXecbTX )
free( pIPXecbTX );
if ( pLocalTarget )
free( pLocalTarget );
return( BAD_MEMORY_ALLOC );
}
/* --------------------------- */
/* initialize ECBs/IPX packets */
/* --------------------------- */
memcpy( pIPXecbRX->Socket, Socket, sizeof(pIPXecbRX->Socket) );
pIPXpktRX->PacketType = IPX_PACKET_TYPE;
pIPXecbRX->FragmentCnt = 2;
pIPXecbRX->Fragment[0].BufAddr = (void *)pIPXpktRX;
pIPXecbRX->Fragment[0].Len = sizeof(IPXHEADER);
pIPXecbRX->Fragment[1].BufAddr = (void *)pIPXbfrRX;
pIPXecbRX->Fragment[1].Len = SEQLEN+IPXdatalen;
memcpy( pIPXecbTX->Socket, Socket, sizeof(pIPXecbTX->Socket) );
pIPXpktTX->PacketType = IPX_PACKET_TYPE;
pIPXecbTX->FragmentCnt = 2;
pIPXecbTX->Fragment[0].BufAddr = (void *)pIPXpktTX;
pIPXecbTX->Fragment[0].Len = sizeof(IPXHEADER);
pIPXecbTX->Fragment[1].BufAddr = (void *)pIPXbfrTX;
memcpy( &pIPXpktTX->DestAddr, Destination, sizeof(NETADDR) );
memcpy( pLocalTarget, Destination, sizeof(INTNETADDR) );
IPXerrno = IPXGetLocalTarget( pLocalTarget );
if ( IPXerrno != IPX_SUCCESS )
{
IPXSocketClose( Socket );
if ( fileflg )
close( fhandle );
free( pIPXbfrRX );
free( pIPXbfrTX );
free( pIPXpktRX );
free( pIPXpktTX );
free( pIPXecbRX );
free( pIPXecbTX );
free( pLocalTarget );
return( BAD_LOCAL_TARGET );
}
memcpy( pIPXecbTX->ImmediateAddr,
pLocalTarget->ImmediateAddr,
sizeof(pIPXecbTX->ImmediateAddr) );
/* =================== */
/* DATA TX/ACK RX LOOP */
/* =================== */
expected_seq = FIRST_SEQ_NUM;
retryTXflg = !TRUE;
retries = 0;
while( TRUE )
{
/* if user chose to break things off, then quit */
if ( USERBREAK )
{
rc = USER_TERMINATED;
break;
}
/* get ready for expected ACK of imminent TX */
IPXListenForPacket( pIPXecbRX );
/* if TX retry is not active, prepare TX buffer */
if ( !retryTXflg )
{
/* fill TX buffer with data from file */
if ( fileflg )
{
lenTX = read( fhandle, pIPXbfrTX+SEQLEN, IPXdatalen );
if ( lenTX == (unsigned)FILE_PROBLEM )
{
IPXCancelEvent( pIPXecbRX );
rc = BAD_FILE_READ;
break;
}
}
/* fill TX buffer with data from buffer */
if ( !fileflg )
{
lenTX = ((*BfrLen < IPXdatalen) ? *BfrLen : IPXdatalen);
memcpy( pIPXbfrTX+SEQLEN, TXptr, lenTX );
TXptr += lenTX;
*BfrLen -= IPXdatalen;
}
/* set sequence number & buffer length */
*pIPXbfrTX = expected_seq;
pIPXecbTX->Fragment[1].Len = SEQLEN+lenTX;
} // end of if ( !retryTXflg )
/* send the data & check result of TX */
IPXSendPacket( pIPXecbTX );
IPXTimeOutRT( pIPXecbTX, IPXto, RTfunc );
IPXerrno = pIPXecbTX->CompletionCode;
if ( IPXerrno != IPX_SUCCESS )
{
/* cancel the pending LISTEN */
IPXCancelEvent( pIPXecbRX );
rc = BAD_TX_TRY;
break;
}
/* ---------------------------------- */
/* RX (ACK to previous TX) is pending */
/* ---------------------------------- */
/* wait for RX to complete, then check result */
IPXTimeOutRT( pIPXecbRX, IPXto, RTfunc );
IPXerrno = pIPXecbRX->CompletionCode;
/* ----------------------------- */
/* ACK was received successfully */
/* ----------------------------- */
if ( IPXerrno == IPX_SUCCESS )
{
/* check that RX was from expected Destination */
if ( memcmp( Destination, &pIPXpktRX->SrceAddr, sizeof(NETADDR) ) )
{
rc = BAD_RX_SRCE_ADDR;
break;
}
/* check that TX/RX sequence in sync */
if ( expected_seq != *pIPXbfrRX )
{
rc = BAD_RX_SEQ_NUM;
break;
}
/* if last TX was EOT, then all done! */
if ( lenTX < IPXdatalen )
{
rc = GOOD_IPX_RETURN;
break;
}
/* otherwise, do next TX */
expected_seq++;
retries = 0;
retryTXflg = !TRUE;
} // end of if ( IPXerrno == IPX_SUCCESS )
/* ------------------- */
/* no ACK was received */
/* ------------------- */
if ( IPXerrno != IPX_SUCCESS )
{
/* if maximum retries have been exhausted, then quit */
if ( retries++ >= IPXtries )
{
rc = BAD_RETRIES;
break;
}
/* otherwise, try RX again */
retryTXflg = TRUE;
} // end of if ( IPXerrno != IPX_SUCCESS )
} // end of while ( TRUE )
/* --------------------------------- */
/* close socket and bring it on home */
/* --------------------------------- */
IPXSocketClose( Socket );
if ( fileflg )
close( fhandle );
free( pIPXbfrRX );
free( pIPXbfrTX );
free( pIPXpktRX );
free( pIPXpktTX );
free( pIPXecbRX );
free( pIPXecbTX );
free( pLocalTarget );
return( rc );
}
/************************************************************************/
/* EOF EOF EOF EOF EOF EOF EOF EOF EOF EOF EOF EOF EOF EOF */
/************************************************************************/